package com.gzc.just.play.last.war.centralserver.achievement;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * AchievementManager 单元测试 - 测试 14 个测试用例
 * 覆盖成就注册、进度更新、奖励领取等功能
 */
@DisplayName("成就管理系统单元测试")
class AchievementManagerTest {

    private AchievementManager achievementManager;
    private AchievementConfig config1;
    private AchievementConfig config2;
    private long playerId = 1001;

    @BeforeEach
    void setUp() {
        achievementManager = new AchievementManager();
        
        config1 = new AchievementConfig(101, "首次胜利", "赢得第一场战斗", 
                                       AchievementType.FIRST_VICTORY, 1, 100, 500, 
                                       false, 1, "icon1", "战斗");
        
        config2 = new AchievementConfig(102, "十连胜", "连赢10场战斗", 
                                       AchievementType.STREAK_VICTORIES, 10, 500, 5000, 
                                       false, 2, "icon2", "战斗");
        
        achievementManager.registerAchievement(config1);
        achievementManager.registerAchievement(config2);
    }

    // ========== 成就注册 ==========

    @Test
    @DisplayName("测试1: 注册成就")
    void testRegisterAchievement() {
        assertNotNull(achievementManager.getAchievementConfig(101));
        assertEquals("首次胜利", achievementManager.getAchievementConfig(101).getName());
    }

    @Test
    @DisplayName("测试2: 获取成就配置")
    void testGetAchievementConfig() {
        AchievementConfig config = achievementManager.getAchievementConfig(101);
        assertEquals(101, config.getAchievementId());
        assertEquals(1, config.getTargetValue());
    }

    @Test
    @DisplayName("测试3: 初始化玩家成就")
    void testInitializePlayerAchievements() {
        achievementManager.initializePlayerAchievements(playerId);
        
        PlayerAchievement pa = achievementManager.getPlayerAchievement(playerId, 101);
        assertNotNull(pa);
        assertFalse(pa.isCompleted());
    }

    // ========== 成就进度 ==========

    @Test
    @DisplayName("测试4: 更新成就进度")
    void testUpdateAchievementProgress() {
        achievementManager.initializePlayerAchievements(playerId);
        boolean completed = achievementManager.updateAchievementProgress(playerId, 101, 1);
        assertTrue(completed);
    }

    @Test
    @DisplayName("测试5: 分步更新成就进度")
    void testProgressivAchievementUpdate() {
        achievementManager.initializePlayerAchievements(playerId);
        
        achievementManager.updateAchievementProgress(playerId, 102, 5);
        PlayerAchievement pa = achievementManager.getPlayerAchievement(playerId, 102);
        assertEquals(5, pa.getCurrentProgress());
        assertFalse(pa.isCompleted());
        
        achievementManager.updateAchievementProgress(playerId, 102, 5);
        assertTrue(pa.isCompleted());
    }

    @Test
    @DisplayName("测试6: 获取玩家成就")
    void testGetPlayerAchievement() {
        achievementManager.initializePlayerAchievements(playerId);
        PlayerAchievement pa = achievementManager.getPlayerAchievement(playerId, 101);
        
        assertNotNull(pa);
        assertEquals(playerId, pa.getPlayerId());
        assertEquals(101, pa.getAchievementId());
    }

    @Test
    @DisplayName("测试7: 获取玩家所有成就")
    void testGetPlayerAchievements() {
        achievementManager.initializePlayerAchievements(playerId);
        List<PlayerAchievement> achievements = achievementManager.getPlayerAchievements(playerId);
        
        assertEquals(2, achievements.size());
    }

    // ========== 成就完成与奖励 ==========

    @Test
    @DisplayName("测试8: 领取成就奖励")
    void testClaimAchievementReward() {
        achievementManager.initializePlayerAchievements(playerId);
        achievementManager.updateAchievementProgress(playerId, 101, 1);
        
        boolean claimed = achievementManager.claimAchievementReward(playerId, 101);
        assertTrue(claimed);
    }

    @Test
    @DisplayName("测试9: 获取已完成的成就")
    void testGetCompletedAchievements() {
        achievementManager.initializePlayerAchievements(playerId);
        achievementManager.updateAchievementProgress(playerId, 101, 1);
        achievementManager.updateAchievementProgress(playerId, 102, 10);
        
        List<PlayerAchievement> completed = achievementManager.getCompletedAchievements(playerId);
        assertEquals(2, completed.size());
    }

    @Test
    @DisplayName("测试10: 获取未领取奖励的成就")
    void testGetUnclaimedAchievements() {
        achievementManager.initializePlayerAchievements(playerId);
        achievementManager.updateAchievementProgress(playerId, 101, 1);
        
        List<PlayerAchievement> unclaimed = achievementManager.getUnclaimedAchievements(playerId);
        assertTrue(unclaimed.size() > 0);
    }

    @Test
    @DisplayName("测试11: 成就完成度百分比")
    void testAchievementCompletionPercentage() {
        achievementManager.initializePlayerAchievements(playerId);
        achievementManager.updateAchievementProgress(playerId, 101, 1);
        
        int percentage = achievementManager.getAchievementCompletionPercentage(playerId);
        assertEquals(50, percentage);
    }

    @Test
    @DisplayName("测试12: 100%完成度")
    void testFullCompletion() {
        achievementManager.initializePlayerAchievements(playerId);
        achievementManager.updateAchievementProgress(playerId, 101, 1);
        achievementManager.updateAchievementProgress(playerId, 102, 10);
        
        int percentage = achievementManager.getAchievementCompletionPercentage(playerId);
        assertEquals(100, percentage);
    }

    @Test
    @DisplayName("测试13: 未初始化玩家返回空列表")
    void testUninitializedPlayerReturnsEmpty() {
        List<PlayerAchievement> achievements = achievementManager.getPlayerAchievements(9999);
        assertTrue(achievements.isEmpty());
    }

    @Test
    @DisplayName("测试14: 添加成就监听器")
    void testAddAchievementListener() {
        TestAchievementListener listener = new TestAchievementListener();
        achievementManager.addListener(listener);
        
        achievementManager.initializePlayerAchievements(playerId);
        assertTrue(listener.initializationCalled);
    }

    // 测试用的监听器
    static class TestAchievementListener implements AchievementManager.AchievementListener {
        boolean initializationCalled = false;
        boolean progressCalled = false;
        boolean completionCalled = false;
        boolean rewardClaimed = false;

        @Override
        public void onAchievementsInitialized(long playerId) {
            initializationCalled = true;
        }

        @Override
        public void onAchievementProgress(long playerId, int achievementId, int progress) {
            progressCalled = true;
        }

        @Override
        public void onAchievementCompleted(long playerId, int achievementId) {
            completionCalled = true;
        }

        @Override
        public void onAchievementRewardClaimed(long playerId, int achievementId, int points, int gold) {
            rewardClaimed = true;
        }
    }

    // ========== 高级测试 ==========

    @Test
    @DisplayName("测试扩展1: 多玩家成就隔离")
    void testMultiPlayerAchievementIsolation() {
        long player1 = 1001;
        long player2 = 1002;
        
        achievementManager.initializePlayerAchievements(player1);
        achievementManager.initializePlayerAchievements(player2);
        
        achievementManager.updateAchievementProgress(player1, 101, 1);
        
        PlayerAchievement pa1 = achievementManager.getPlayerAchievement(player1, 101);
        PlayerAchievement pa2 = achievementManager.getPlayerAchievement(player2, 101);
        
        assertTrue(pa1.isCompleted());
        assertFalse(pa2.isCompleted());
    }

    @Test
    @DisplayName("测试扩展2: 成就奖励信息")
    void testAchievementRewardInfo() {
        assertNotNull(config1.getRewardPoints());
        assertNotNull(config1.getRewardGold());
        assertEquals(100, config1.getRewardPoints());
        assertEquals(500, config1.getRewardGold());
    }

    @Test
    @DisplayName("测试扩展3: 并发更新成就进度")
    void testConcurrentProgressUpdate() throws InterruptedException {
        achievementManager.initializePlayerAchievements(playerId);
        
        Thread t1 = new Thread(() -> 
            achievementManager.updateAchievementProgress(playerId, 102, 5)
        );
        Thread t2 = new Thread(() -> 
            achievementManager.updateAchievementProgress(playerId, 102, 5)
        );
        
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        
        PlayerAchievement pa = achievementManager.getPlayerAchievement(playerId, 102);
        assertEquals(10, pa.getCurrentProgress());
    }

    @Test
    @DisplayName("测试扩展4: 成就配置的属性")
    void testAchievementConfigAttributes() {
        AchievementConfig config = achievementManager.getAchievementConfig(102);
        assertEquals("十连胜", config.getName());
        assertEquals("连赢10场战斗", config.getDescription());
        assertEquals(10, config.getTargetValue());
    }

    @Test
    @DisplayName("测试扩展5: 重复领取奖励检查")
    void testDuplicateRewardClaim() {
        achievementManager.initializePlayerAchievements(playerId);
        achievementManager.updateAchievementProgress(playerId, 101, 1);
        
        boolean firstClaim = achievementManager.claimAchievementReward(playerId, 101);
        boolean secondClaim = achievementManager.claimAchievementReward(playerId, 101);
        
        assertTrue(firstClaim);
        assertFalse(secondClaim);
    }
}
